﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq;
using BluePortal.Framework;

namespace BluePortal.Medias.Core
{
    public class BCChannel : AbstractBusinessComponent
    {
        #region private methods
        private void InternalDelete(Channel channel)
        {
            var selectedChannel = Context.Channels.SingleOrDefault(ch => ch.CHID == channel.CHID);
            if (selectedChannel != null)
            {
                Context.Channels.DeleteOnSubmit(selectedChannel);
                Context.SubmitChanges();
            }
        }

        private void InternaAdd(Channel channel)
        {
            if (channel.CHID == Guid.Empty)
                channel.CHID = Guid.NewGuid();
            Context.Channels.InsertOnSubmit(channel);
            Context.SubmitChanges();
        }

        private void InternalUpdate(Channel channel)
        {
            Channel selectedChannel = Context.Channels.SingleOrDefault(ch => ch.CHID == channel.CHID);

            if (selectedChannel != null)
            {
                selectedChannel.ChannelName = channel.ChannelName;
                selectedChannel.ChannelDescription = channel.ChannelDescription;
                selectedChannel.ChannelLogo = channel.ChannelLogo;
                selectedChannel.IsPrivate = channel.IsPrivate;
                selectedChannel.AllowLive = channel.AllowLive;

                Context.SubmitChanges();
            }
        }

        #endregion

        #region Internal Finders

        public IQueryable<Channel> QueryFindAll()
        {
            var query = from t in Context.Channels
                        select t;

            return query;
        }

        public IQueryable<Channel> QueryFindByMedia(Guid ID)
        {
            
            var query = from t in Context.Channels
                        from vt in t.MediaChannels
                        where vt.ID == ID
                        select t;
            return query;

        }

        public IQueryable<Channel> QueryFindAllByMedia(Guid ID)
        {
            var query = from c in Context.Channels
                        select c;

            foreach (Channel c in query)
            {
                var q = from vc in Context.MediaChannels where vc.CHID == c.CHID && vc.ID == ID select vc;
                foreach (MediaChannel vc in q)
                    c.MediaChannels.Add(vc);
            }
            return query;
        }

        public IQueryable<Channel> QueryFindByLoginNameWithMedia(string loginName)
        {
            DataLoadOptions ds = new DataLoadOptions();
            ds.LoadWith<MediaChannel>(vc => vc.Media);
            Context.LoadOptions = ds;

            var query = from c in Context.Channels
                        from cu in c.ChannelUsers
                        where cu.LoginName == loginName
                        select c;
            foreach (Channel c in query)
            {
                var cq = CompiledQuery.Compile((EntitiesDataContext context, Guid channelId) =>
                    (from vc in context.MediaChannels
                     where vc.CHID == channelId
                     select vc).Take(3));

                foreach (var vc in cq(Context, c.CHID))
                    c.MediaChannels.Add(vc);

                c.MemberCount = (from cu in Context.ChannelUsers where c.CHID == cu.CHID select cu).Count();
                c.VideoCount = (from vc in Context.MediaChannels where c.CHID == vc.CHID select vc).Count();
                var q = from cu in Context.ChannelUsers where cu.LoginName == loginName && cu.CHID == c.CHID select cu;
                foreach (ChannelUser cu in q)
                    c.ChannelUsers.Add(cu);
            }
            return query; 
        }

        public IQueryable<Channel> QueryFindByOwnerWithMedia(string owner)
        {
            DataLoadOptions ds = new DataLoadOptions();
            ds.LoadWith<MediaChannel>(vc => vc.Media);
            Context.LoadOptions = ds;

            var query = from c in Context.Channels
                        where c.Owner == owner
                        select c;
            foreach (Channel c in query)
            {
                var cq = CompiledQuery.Compile((EntitiesDataContext context, Guid channelId) =>
                    (from vc in context.MediaChannels
                     where vc.CHID == channelId
                     select vc).Take(3));

                foreach (var vc in cq(Context, c.CHID))
                    c.MediaChannels.Add(vc);

                c.MemberCount = (from cu in Context.ChannelUsers where c.CHID == cu.CHID select cu).Count();
                c.VideoCount = (from vc in Context.MediaChannels where c.CHID == vc.CHID select vc).Count();
                var q = from cu in Context.ChannelUsers where cu.LoginName == owner && cu.CHID == c.CHID select cu;
                foreach (ChannelUser cu in q)
                    c.ChannelUsers.Add(cu);
            }
            return query;
        }

        public IQueryable<Channel> QueryFindAllWithMedia(string loginName)
        {
            DataLoadOptions ds = new DataLoadOptions();
            ds.LoadWith<MediaChannel>(vc => vc.Media);
            Context.LoadOptions = ds;

            var query = from c in Context.Channels
                        orderby c.CreationDate descending
                        select c;

            foreach (Channel c in query)
            {
                var cq = CompiledQuery.Compile((EntitiesDataContext context, Guid channelId) =>
                    (from vc in context.MediaChannels
                    where vc.CHID == channelId
                    select vc).Take(3));
                
                foreach (var vc in cq(Context, c.CHID))
                    c.MediaChannels.Add(vc);

                c.MemberCount = (from cu in Context.ChannelUsers where c.CHID == cu.CHID select cu).Count();
                c.VideoCount = (from vc in Context.MediaChannels where c.CHID == vc.CHID select vc).Count();
                var q = from cu in Context.ChannelUsers where cu.LoginName == loginName && cu.CHID == c.CHID select cu;
                foreach (ChannelUser cu in q)
                    c.ChannelUsers.Add(cu);
            }

            return query;
        }

        public IQueryable<Channel> QueryFindTopPopularWithMedia(string loginName, int count)
        {
            DataLoadOptions ds = new DataLoadOptions();
            ds.LoadWith<MediaChannel>(vc => vc.Media);
            Context.LoadOptions = ds;

            var query = from c in Context.Channels
                        orderby c.ChannelUsers.Count descending
                        select c;

            foreach (Channel c in query)
            {
                var cq = CompiledQuery.Compile((EntitiesDataContext context, Guid channelId) =>
                    (from vc in context.MediaChannels
                     where vc.CHID == channelId
                     select vc).Take(3));

                foreach (var vc in cq(Context, c.CHID))
                    c.MediaChannels.Add(vc);

                c.MemberCount = (from cu in Context.ChannelUsers where c.CHID == cu.CHID select cu).Count();
                c.VideoCount = (from vc in Context.MediaChannels where c.CHID == vc.CHID select vc).Count();
                var q = from cu in Context.ChannelUsers where cu.LoginName == loginName && cu.CHID == c.CHID select cu;
                foreach (ChannelUser cu in q)
                    c.ChannelUsers.Add(cu);
            }

            return query.Take(count);
        }

        public IQueryable<Channel> QueryFindWithMedia(string loginName, Guid chid)
        {
            DataLoadOptions ds = new DataLoadOptions();
            ds.LoadWith<MediaChannel>(vc => vc.Media);
            Context.LoadOptions = ds;

            var query = from c in Context.Channels
                        where c.CHID == chid
                        select c;

            foreach (Channel c in query)
            {
                var cq = CompiledQuery.Compile((EntitiesDataContext context, Guid channelId) =>
                    (from vc in context.MediaChannels
                     where vc.CHID == channelId
                     select vc).Take(3));

                foreach (var vc in cq(Context, c.CHID))
                    c.MediaChannels.Add(vc);

                c.MemberCount = (from cu in Context.ChannelUsers where c.CHID == cu.CHID select cu).Count();
                c.VideoCount = (from vc in Context.MediaChannels where c.CHID == vc.CHID select vc).Count();
                var q = from cu in Context.ChannelUsers where cu.LoginName == loginName && cu.CHID == c.CHID select cu;
                foreach (ChannelUser cu in q)
                    c.ChannelUsers.Add(cu);
            }

            return query;
        }

        public IQueryable<Channel> QueryFindByMedia(Media media)
        {
            AssertNotNull(media, "media");
            return QueryFindByMedia(media.ID);
        }
        #endregion

        #region IBasicService Members
        
        public Channel FindByID(Guid chid)
        {
            return Context.Channels.SingleOrDefault(c => c.CHID == chid);
        }

        public void Create(Channel channel)
        {
            AssertNotNull(channel, "channel");
            InternaAdd(channel);
        }

        public void Update(Channel channel)
        {
            AssertNotNull(channel, "channel");
            InternalUpdate(channel);
        }

        public void Delete(Channel channel)
        {
            AssertNotNull(channel, "channel");
            InternalDelete(channel);
        }

        public void Add(Channel channel, Media media)
        {
            AssertNotNull(channel, "channel");
            AssertNotNull(media, "Video");
            Add(channel.CHID, media.ID);
        }

        public void Add(Guid chid, Guid ID)
        {
            MediaChannel Result = new MediaChannel() { CHID = chid, ID = ID };
            Context.MediaChannels.InsertOnSubmit(Result);
            Context.SubmitChanges();
        }

        public void Remove(Channel channel, Media media)
        {
            AssertNotNull(channel, "channel");
            AssertNotNull(media, "media");
            Remove(channel.CHID, media.ID);
        }

        public void Remove(Guid chid, Guid ID)
        {
            var MediaChannel = from vc in Context.MediaChannels
                               where vc.CHID == chid && vc.ID == ID
                               select vc;

            if (MediaChannel.Count() > 0)
            {
                foreach (MediaChannel vc in MediaChannel)
                {
                    Context.MediaChannels.DeleteOnSubmit(vc);
                }
                Context.SubmitChanges();
            }
        }


        public FindResult<Channel> FindAllByMedia(Guid id, FindParameters f)
        {
            return ToFindResult<Channel>(QueryFindAllByMedia(id), f);
        }

        public FindResult<Channel> FindAll(FindParameters f)
        {
            return ToFindResult<Channel>(QueryFindAll(), f);
        }

        public FindResult<Channel> FindByMediaID(Guid ID, FindParameters f)
        {
            return ToFindResult<Channel>(QueryFindByMedia(ID), f);
        }

        public FindResult<Channel> FindByMedia(Media media, FindParameters f)
        {
            return ToFindResult<Channel>(QueryFindByMedia(media), f);
        }

        public FindResult<Channel> FindByLoginNameWithMedia(string loginName, FindParameters f)
        {
            return ToFindResult<Channel>(QueryFindByLoginNameWithMedia(loginName), f);
        }

        public FindResult<Channel> FindAllWithMedia(string loginName, FindParameters f)
        {
            return ToFindResult<Channel>(QueryFindAllWithMedia(loginName), f);
        }

        public FindResult<Channel> FindWithMedia(string loginName, Guid chid, FindParameters f)
        {
            return ToFindResult<Channel>(QueryFindWithMedia(loginName, chid), f);
        }

        public FindResult<Channel> FindByOwnerWithMedia(string owner, FindParameters f)
        {
            return ToFindResult<Channel>(QueryFindByOwnerWithMedia(owner), f);
        }

        public FindResult<Channel> FindTopPopularWithMedia(string loginName, int count)
        {
            return ToFindResult<Channel>(QueryFindTopPopularWithMedia(loginName, count), null);
        }

        #endregion
    }
}
